import json
import os

import msgpack
from beacontools import parse_packet

from App.ext import redis, mongo, db
from App.models.bluetooth_gateway_model import Users
from App.settings import BASE_DIR

TRAIN_DIR = os.path.join(BASE_DIR, "trainData")


def get_user(mark):
    user = Users.query.filter_by(mark=mark).first()
    if not user:  # 用户不存在创建用户
        user = Users(mark=mark)
        db.session.add(user)
        db.session.commit()
    return user

# 保存蓝牙信标数据
class IbeaconData(object):
    def __init__(self, data, is_raw=True):
        self.data = data
        self.old_line = redis.get("old_line") or 0
        self.new_line = redis.get("new_line") or 0
        self.is_raw = is_raw

    # 解析二进制数据
    def parseDataByRequestDate(self):
        """
        解析 request.data中的原始数据
        :return: [{"mac": "信标的MAC地址", "UUID": "信标的UUID标识",
         "rssi": "信标的强度", "major": "标识信标的楼号", "minor": "信标的楼层位置",
          "tx_power": "信标发射的功率"}]
        """
        ret = []
        for d in msgpack.unpackb(self.data)[b'devices']:
            # parse iBeacon data
            advData = d[8:]
            adv = parse_packet(advData)
            # 只要含有广告的
            if adv == None:
                continue
            mac = "{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}".format(d[1], d[2], d[3], d[4], d[5], d[6])
            rssi = d[7] - 256
            UUID = adv.uuid
            major = adv.major
            minor = adv.minor
            tx_power = adv.tx_power

            ret.append({"mac": mac, "UUID": UUID, "rssi": rssi, "major": major, "minor": minor, "tx_power": tx_power})
        return ret

    # 数据是ajax发送的  还是原始数据发送的
    def getData(self):
        if self.is_raw:
            return self.parseDataByRequestDate()
        else:
            return self.data

    # 保存数据(保存到本地, 或者mongodb)
    @staticmethod
    def getIbeaconCollectionMethod():
        """
        判断返回的数据是 收集单个的,还是收集多个的
        :return: True表示单个   False 表示多个(理论上空间的)
        """

        # 从redis 缓存中 获取collection_method 值 one 就是保存单个信标的   any是保存所有信标处理后的原始信息
        collection_method = redis.get("collection_method") == "one"
        return collection_method

    # 保存信标数据到文件
    def saveToFile(self, mac):
        data = self.getData()
        rssi_list = self.filterMacRssi(data).get(mac)
        if self.getIbeaconCollectionMethod():
            path = os.path.join(TRAIN_DIR, f"{mac}.txt")  # 要打开的文件
            if os.path.exists(path):
                a = ""
            else:
                a = f"{self.new_line}m "

            if rssi_list:
                with open(path, "a") as f:
                    # 如果 a 并且新行
                    if self.old_line == self.new_line:
                        f.write(" ")
                    else:
                        if a:
                            f.write(a)
                        else:
                            f.write(f"\r\n {self.new_line} ")

                    dt = " ".join(rssi_list)
                    f.write(dt)
        else:
            path = os.path.join(TRAIN_DIR, f"{self.new_line}.txt")

            with open(path, "a") as f:
                f.write(f"{json.dumps(data)}\r\n")

    @staticmethod
    def get_mac_from_mongo(mac, distance):
        ibeacon = mongo.db.oneIbeacon.find_one({"mac": mac, "distance": distance})
        return ibeacon

    # 保存到mongodb
    def saveToMongoDB(self, mac):
        data = self.getData()
        rssi_list = self.filterMacRssi(data).get(mac)
        if self.getIbeaconCollectionMethod():
            # 表名  单个信标  [{mac:"mac地址", diatance:0.8, rssi:[...]}]
            ibeacon = self.get_mac_from_mongo(mac, self.new_line)
            if ibeacon:
                ibeacon.rssi += rssi_list
                ibeacon.save()
            else:
                mongo.db.oneIbeacon.insert_one({"mac": mac, "distance": self.new_line, "rssi": rssi_list})
        else:
            # 表明  多个信标 [mark:1,data:[{"mac":"mac地址","rssi":-58"},...]]
            mongo.db.manyIbeacon.insert_one({"distance": self.new_line, "data": data})

    # 保存到 mysql
    def saveToMydql(self):
        pass

    # 过滤信标数据
    @staticmethod
    def filterMacRssi(data):
        """
        过滤信标数据
        :param data: 需要的数据  [{"mac": "","rssi": -65}]  这两个字段是必须的
        :return: {"mac":[-65,-48...]}
        """
        ret = {}
        for item in data:
            if item.get("mac") in ret:
                ret[item.get("mac")].append(item.get("rssi"))
                continue
            ret[item.get("mac")] = [item.get("rssi")]
        return ret

